// 正则可视化工具: https://regexper.com/
// vue3 采用的不是正则表达式，而是一个字符一个字符去解析
/** 匹配标签名 */
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;

// 允许 xxx:xxx ，冒号前面为命名空间
// 下面语句中 ?: 表示该组并不用于捕获，而是用于聚成一个整体供第二个?使用
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
/** 匹配到的分组是一个标签名(不包含命名空间)，例如 <div ，匹配到的是开始标签的名字 */
export const startTagOpen = new RegExp(`^<${qnameCapture}`);
// /^<((?:[a-zA-Z_][\-\.0-9_a-zA-Z]*\:)?[a-zA-Z_][\-\.0-9_a-zA-Z]*)/
// console.log(startTagOpen);

// 匹配的内容是 </xxxx> 最终匹配到的分组就是结束标签的名字
export const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);
// /^<\/((?:[a-zA-Z_][\-\.0-9_a-zA-Z]*\:)?[a-zA-Z_][\-\.0-9_a-zA-Z]*)[^>]*>/
// console.log(endTag);

// 匹配属性
// 第一个匹配到的分组是属性名，第二个分组是 = ，第三个分组是属性值
export const attribute =
  /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
// 匹配开始标签的结束部分，开始标签可能是自闭合的，如 <br />。
export const startTagClose = /^\s*(\/?)>/;
// 匹配插值语法 {{ xxxx }} ，匹配到的是 xxxx
export const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;

// 目标语法树
// {
//   tag: 'div',
//   type: 1,
//   attrs: [
//     { name: "id", value: "app" },
//     { name: "class", value: "red" },
//     parent: null,
//     children: []
//   ],
// }

// 对模板进行编译处理
function parseHTML(html) {
  function start(tag, attrs) {
    console.log("start", tag, attrs);
  }
  function chars(text) {
    console.log("chars", text);
  }
  function end(tag) {
    console.log("end", tag);
  }
  function advance(n) {
    html = html.substring(n);
  }
  // html 最开始肯定是一个尖角号
  html = html.trim();
  function parseStartTag() {
    const start = html.match(startTagOpen);
    if (start) {
      const match = {
        tagName: start[1], // 标签名
        attrs: [],
      };
      advance(start[0].length);
      let attr, end;
      while (
        !(end = html.match(startTagClose)) &&
        (attr = html.match(attribute))
      ) {
        // 如果不是开始标签的结束标志，则一直匹配下去
        // 如果value用双引号包裹，则使用 attr[3]，如果用单引号包裹，则使用 attr[4]，如果没有引号包裹，则使用 attr[5]
        match.attrs.push({
          name: attr[1],
          value: attr[3] || attr[4] || attr[5] || true,
        });
        advance(attr[0].length);
      }
      if (end) {
        advance(end[0].length);
      }
      return match;
    }
    // 表示不是开始标签
    return false;
  }
  function skipWhitespace() {
    let text = html.match(/^\s*/);
    if (text) {
      advance(text[0].length);
    }
  }
  while (html) {
    // skipWhitespace();
    let textEnd = html.indexOf("<");
    // 如果 textEnd 为 0，说明是一个开始标签或结束标签
    // 如果 textEnd > 0, 说明是文本的结束位置
    if (textEnd === 0) {
      const startTagMatch = parseStartTag(); // 开始标签的匹配
      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs);
        console.log(startTagMatch);
        continue;
      }
      const endTagMatch = html.match(endTag); // 结束标签的匹配
      if (endTagMatch) {
        end(endTagMatch[1]);
        advance(endTagMatch[0].length);
        continue;
      }
    } else if (textEnd > 0) {
      let text = html.substring(0, textEnd);
      chars(text);
      advance(textEnd);
      continue;
    }
  }
}

/** 对模板进行编译处理 */
export function compileToFunction(template) {
  // 1. 将 template 转换成 ast 语法树
  let ast = parseHTML(template);
  // 2. render 方法执行后的返回结果就是虚拟 DOM
  // console.log("@@2", template);
}
